import layui from 'layui';
import { KeyCode, ClassName, MODULE_NAME } from './config';

layui.define(['jquery', 'layer'], function(exports) {
  const $ = layui.jquery;
  const layer = layui.layer;

  const render = function(data, getIcon) {
    const that = this;
    const iterator = function(data, isRoot = true, tips = []) {
      let html = `<ul class="${ClassName.menu}${isRoot ? '' : ' ' + ClassName.isSubmenu}" role="menu">`;

      $.each(data, function(_, t) {
        const id        = t[that.config.keyId];
        const children  = t[that.config.keyChildren];
        const label     = t[that.config.keyLabel];
        const path      = t[that.config.keyPath];
        const count     = $.type(t[that.config.keyCount]) === 'boolean' ? 0 : +t[that.config.keyCount];
        const icon      = $.trim($.type(getIcon) === 'function' ? getIcon(t) : t[that.config.keyIcon]);

        const hasChildren = $.isArray(children) && children.length > 0;
        const itemClass   = [ClassName.item];

        if (hasChildren) {
          itemClass.push(ClassName.hasMenu);
        }

        if (that.config.selected === id) {
          itemClass.push(hasChildren ? ClassName.isOpened : ClassName.isActive); // 包含子导航则展开
        }

        const newTips = tips.slice(0);
        newTips.push(label);

        const itemContent = [
          `<div class="${ClassName.inner}">`,
          icon ? `<i class="${ClassName.icon} ${icon}"></i>` : '',
          `<span class="${ClassName.label}">${label}</span>`,
          count > 0 ? `<span class="${ClassName.badge}">${count > that.config.maxCount ? `${that.config.maxCount}+` : count}</span>` : '',
          hasChildren ? `<i class="${ClassName.arrow} layui-icon layui-icon-right"></i>` : '',
          `</div>`,
          hasChildren ? iterator(children, false, newTips) : ''
        ];

        // 如果当前导航包含子导航，作用其本身的链接失效
        html += `<li class="${$.trim(itemClass.join(' '))}" role="menuitem" data-id="${id}" data-label="${label}" data-level="${newTips.length}" data-tips="${newTips.join('/')}"${!hasChildren && path ? (` data-path="${path}"`) : ''}>${itemContent.join('')}</li>`;
      });
      html += '</ul>';
      return html;
    };
    return $.isArray(data) ? iterator(data) : '';
  };

  const NavMenu = function(options) {
    this.config = $.extend({ selected: null, maxCount: 99 }, KeyCode, options);
    this.$elem = null;
    this.data = [];
  };

  NavMenu.prototype.render = function(elem, data, getIcon) {
    this.$elem = $(elem);
    this.data = data;
    this.$elem.html(render.call(this, data, getIcon));
    this.bindEvents();
  };

  NavMenu.prototype.select = function(target) {
    if (!this.$elem.length) return;
    const $old    = this.$elem.find(`.${ClassName.isActive}`);
    const $target = $(`[data-id="${target}"]`);

    if (!$target.hasClass(ClassName.hasMenu)) {
      $old.removeClass(ClassName.isActive);
      $target.addClass(ClassName.isActive);
    }
  };

  NavMenu.prototype.flex = function() {
    if (!this.$elem.length) return;
    const flag  = arguments.length ? arguments[0] : 'toggle';
    const $menu = this.$elem.children('.' + ClassName.menu);
    if (flag === 'toggle') {
      $menu.toggleClass(ClassName.isShrink);
    } else {
      $menu[flag ? 'addClass' : 'removeClass'](ClassName.isShrink);
    }
  };

  NavMenu.prototype.bindEvents = function() {
    if (!this.$elem.length) return;
    const $menu = this.$elem.children(`.${ClassName.menu}`);
    const othis = this;

    $menu.on(`click.${MODULE_NAME}`, `.${ClassName.item}`, function(e) {
      e.stopPropagation();
      const $this = $(this);
      const $subMenu = $this.children(`.${ClassName.menu}.${ClassName.isSubmenu}`);
      const $other = $this.siblings();
      const $otherSubMenu = $other.children(`.${ClassName.menu}.${ClassName.isSubmenu}`);
      const target = $this.data('id');
      const level = $this.data('level');
      // 如果是第一层采用点击下拉
      if (level === 1) {
        $other.removeClass(ClassName.isOpened);
        $otherSubMenu.slideUp(200);
        $this.toggleClass(ClassName.isOpened);
        $this.hasClass(ClassName.isOpened) ? $subMenu.slideDown(200) : $subMenu.slideUp(200);
      }
      othis.select(target);
    });

    $(document).on(`mouseenter.${MODULE_NAME}`, `.${ClassName.menu} .${ClassName.item}`, function() {
      const $this = $(this);
      const $target = $this.children(`.${ClassName.menu}.${ClassName.isSubmenu}`);
      const $window = $(window);
      const isLvOne = $this.data('level') === 1;
      const isShrink = $menu.hasClass(ClassName.isShrink);
      const thisTop = $this.offset().top;
      const thisLeft = $this.offset().left;
      const style = {};
      let wrapTop;
      let windowWidth;
      let windowHeight;
      let targetHeight;
      let maxHeight;

      if (isLvOne && !isShrink) return; // 移除第一层

      if ($this.hasClass(ClassName.hasMenu)) {
        $this.addClass(ClassName.isHover);
        wrapTop = $menu.offset().top;
        windowWidth = $window.width();
        windowHeight = $window.height();
        targetHeight = $target.height();
        maxHeight = windowHeight - wrapTop - 5;

        if (targetHeight >= maxHeight) {
          style.maxHeight = maxHeight;
          style.overflowY = 'auto';
        }

        if (thisLeft + $this.width() * 2.5 + 10 >= windowWidth) {
          style.maxWidth = Math.max(0, windowWidth - $target.offset().left - 10);
        }

        if (thisTop + targetHeight > windowHeight) {
          style.top = windowHeight - thisTop - Math.min(targetHeight, maxHeight) - 5;
        }

        $target.css(style);
      } else {
        isLvOne && isShrink && $this.data('index', layer.tips($this.data('tips'), $this, {
          tips: 2,
          time: 0
        }));
      }
    }).on(`mouseleave.${MODULE_NAME}`, `.${ClassName.menu} .${ClassName.item}`, function(e) {
      const $this = $(this);
      const $target = $this.children(`.${ClassName.menu}.${ClassName.isSubmenu}`);
      const isLvOne = $this.data('level') === 1;
      const isShrink = $menu.hasClass(ClassName.isShrink);

      $this.removeClass(ClassName.isHover);

      if (isLvOne && !isShrink) return; // 移除第一层

      $this.hasClass(ClassName.hasMenu) ? $target.css({
        position : '',
        maxWidth : '',
        maxHeight: '',
        overflowY: '',
        top      : ''
      }) : layer.close($this.data('index'));
    });
  };

  exports(MODULE_NAME, NavMenu);
});
